using System.Collections.Generic;
using Godot;
using System;
using GDArray = Godot.Collections.Array;

namespace Box;

public partial class ProcessTreeGraphEditor : GraphEdit
{
	
	NodeSelectPopupMenu select_menu;
	Vector2 AddNodePosition = Vector2.Zero;

	Dictionary<Node,Node> selects = new Dictionary<Node, Node>();

	public PropertyPanel PropertyPanel;

	public ProcessNodeControl RootNode = new ProcessNodeControl();

	public void Init(PropertyPanel property_panel) {
		this.PropertyPanel = property_panel;
	}

	public ProcessTreeGraphEditor() {
		RootNode.Name = "Root";
		RootNode.Setting("res://source/process_tree_editor/node/root_node.json");
		AddChild(RootNode);
	}

	public override void _Ready()
	{

		select_menu = GetNode<NodeSelectPopupMenu>("NodeSelectPopupMenu");

		ConnectionRequest += _onConnectRequest;
		DisconnectionRequest += _onDisconnectRequest;

		NodeSelected += _onNodeSelected;
		NodeDeselected += _onNodeDeselected;

		PopupRequest += mouse_position => {
			AddNodePosition = (mouse_position + ScrollOffset) / Zoom;
			
			select_menu.Position = new Vector2I((int)mouse_position.X,(int)mouse_position.Y);
			select_menu.Show();
		};
	}

	public void AddProcessTreeNode(ProcessNodeControl node) {
		node.PositionOffset = AddNodePosition;
		AddChild(node);
	}

	ProcessNodeControlPort GetOutputPort(ProcessNodeControl node,int slot) {
		return node.Slots[slot-1].Right;
	}

	ProcessNodeControlPort GetInputPort(ProcessNodeControl node,int slot) {
		return node.Slots[slot-1].Left;
	}

	public void _onNodeSelected(Node node) {
		selects[node] = node;

		foreach(Node n in PropertyPanel.Properties.GetChildren()) {
			PropertyPanel.Properties.RemoveChild(n);
		}

		ProcessNodeControl ptn = node as ProcessNodeControl;

		foreach(var p in ptn.PropertyControls) {
			PropertyPanel.Properties.AddChild(p);
		}
	}

	public void _onNodeDeselected(Node node) {
		selects.Remove(node);
	}

	public void _onConnectRequest(StringName from_name,long from_port,StringName to_name,long to_port) {
		ProcessNodeControl from_node = GetNode<ProcessNodeControl>(from_name.ToString());
		ProcessNodeControl to_node = GetNode<ProcessNodeControl>(to_name.ToString());

		if(ConnectNode(from_name,(int)from_port,to_name,(int)to_port) == Error.Ok) {
			from_node.onConnectionRequest(GetOutputPort(from_node,(int)from_port),GetInputPort(to_node,(int)to_port));
		}
		
	}

	public void _onDisconnectRequest(StringName from_name,long from_port,StringName to_name,long to_port) {
		ProcessNodeControl from_node = GetNode<ProcessNodeControl>(from_name.ToString());
		ProcessNodeControl to_node = GetNode<ProcessNodeControl>(to_name.ToString());

		DisconnectNode(from_name,(int)from_port,to_name,(int)to_port);
		from_node.onDisconnectionRequest(GetOutputPort(from_node,(int)from_port),GetInputPort(to_node,(int)to_port));
	}

	public void CleraAllNodes() {
		selects.Clear();

		foreach(Node node in GetChildren()) {
			if(node is ProcessNodeControl) {
				DeleteNode(node as ProcessNodeControl);
			}
			
		}

		foreach(Node node in GetChildren()) {
			if(node is ProcessNodeControl) {
				if(node.Name != "Root") {
					node.GetParent().RemoveChild(node);
					node.QueueFree();
				}
			}
		}
	}

	public void DeleteNode(ProcessNodeControl node) {
		if(node == null) return;
		if(node.Name == "Root")  {
			foreach(var port in node.OutputPorts.Values) {
				foreach(var connect in port.Connects.ToArray()) {
					connect.Connects.Remove(port);
					port.Connects.Remove(connect);
					_onDisconnectRequest(node.Name,port.SlotID,connect.Node.Name,connect.SlotID);
				}
			}
			return;
		}

		foreach(var port in node.OutputPorts.Values) {
			foreach(var connect in port.Connects.ToArray()) {
				connect.Connects.Remove(port);
				port.Connects.Remove(connect);
				_onDisconnectRequest(node.Name,port.SlotID,connect.Node.Name,connect.SlotID);
			}
		}

		foreach(var port in node.InputPorts.Values) {
			foreach(var connect in port.Connects.ToArray()) {
				connect.Connects.Remove(port);
				port.Connects.Remove(connect);
				_onDisconnectRequest(connect.Node.Name,connect.SlotID,node.Name,port.SlotID);
			}
		}

		foreach(Node n in PropertyPanel.GetChildren()) {
			PropertyPanel.RemoveChild(n);
		}
	}

    public override void _Input(InputEvent @event)
    {
		if(@event is InputEventKey) {
			if(@event.IsActionReleased("delete_node")) {
				foreach(Node node in selects.Values) {
					DeleteNode(node as ProcessNodeControl);
					if(node.Name != "Root") {
						node.QueueFree();
					}
				}
				// foreach(Node node in selects.Values) {
				// 	node.QueueFree();
				// }

				selects.Clear();
			}
		}
    }
}
